package com.leyou.auth.service.impl;

import com.leyou.auth.config.JwtProperties;
import com.leyou.auth.service.IauthService;
import com.leyou.common.auth.entity.AppInfo;
import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.CookieUtils;
import com.leyou.auth.entity.ApplicationInfo;
import com.leyou.auth.mapper.ApplicationInfoMapper;
import com.leyou.user.UserClient;
import com.leyou.user.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class IauthServiceImpl implements IauthService {

    @Autowired
    private UserClient userClient;

    @Autowired
    private JwtProperties pro;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    ApplicationInfoMapper infoMapper;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    private static final String USER_ROLE = "admin";

    @Override
    public void login(String username, String password, HttpServletResponse response) {

        try {
            UserDTO userDTO = userClient.login(username, password);

            UserInfo userInfo = BeanHelper.copyProperties(userDTO, UserInfo.class);

            userInfo.setRole(USER_ROLE);

            String token = JwtUtils.generateTokenExpireInMinutes(userInfo, pro.getPrivateKey(), pro.getUser().getExpire());

            CookieUtils.newBuilder()
                    .domain(pro.getUser().getCookieDomain())
                    .name(pro.getUser().getCookieName())
                    .value(token)
                    .httpOnly(true)
                    .maxAge(pro.getUser().getExpire() * 60)
                    .response(response)
                    .build();
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.USER_NOT_FOUND);
        }
    }

    @Override
    public UserInfo verify(HttpServletRequest request, HttpServletResponse response) {
        try {
            String token = CookieUtils.getCookieValue(request, pro.getUser().getCookieName());

            Payload<UserInfo> infoFromToken = JwtUtils.getInfoFromToken(token, pro.getPublicKey(), UserInfo.class);

            if (redisTemplate.hasKey(infoFromToken.getId())) {
                throw new LyException(ExceptionEnum.VERIFY_FAIL);
            }

            String newToken = JwtUtils.generateTokenExpireInMinutes(infoFromToken.getInfo(), pro.getPrivateKey(), pro.getUser().getExpire());

            CookieUtils.newBuilder()
                    .response(response)
                    .httpOnly(true)
                    .maxAge(pro.getUser().getExpire() * 60)
                    .name(pro.getUser().getCookieName())
                    .value(newToken)
                    .domain(pro.getUser().getCookieDomain())
                    .build();

            UserInfo info = infoFromToken.getInfo();

            return info;
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.VERIFY_FAIL);
        }


    }

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response) {
        try {
            String token = CookieUtils.getCookieValue(request, pro.getUser().getCookieName());

            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, pro.getPublicKey(), UserInfo.class);

            String id = payload.getId();

            Date expiration = payload.getExpiration();

            if (System.currentTimeMillis() + 5000 < expiration.getTime()) {
                redisTemplate.opsForValue().set(id, "", expiration.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
            }

            Cookie cookie = new Cookie(pro.getUser().getCookieName(), "");
            cookie.setDomain(pro.getUser().getCookieDomain());
            cookie.setMaxAge(0);
            cookie.setPath("/");

            response.addCookie(cookie);
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.DELETE_FAIL);
        }

    }

    @Override
    public String authorize(Long id, String secret) {
        ApplicationInfo app = infoMapper.selectByPrimaryKey(id);
        if (null == app) {
            throw new LyException(ExceptionEnum.INVALID_SERVER_ID_SECRET);
        }
        if (!passwordEncoder.matches(secret, app.getSecret())) {
            throw new LyException(ExceptionEnum.INVALID_SERVER_ID_SECRET);
        }
        List<Long> queryTargetIdList = infoMapper.queryTargetIdList(id);

        AppInfo appInfo = new AppInfo();
        appInfo.setId(app.getId());
        appInfo.setServiceName(app.getServiceName());
        appInfo.setTargetList(queryTargetIdList);

        return JwtUtils.generateTokenExpireInMinutes(appInfo, pro.getPrivateKey(), pro.getApp().getExpire());
    }


}
